package nl.windgazer.arachne.services.messages;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.tapestry5.internal.services.MapMessages;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.OrderedConfiguration;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.services.Context;

public class MessageInterceptorStorageImp implements MessageInterceptorStorage {
	
	final static Logger logger = Logger.getLogger(MessageInterceptorStorageImp.class);

	//InMemory storage of translated messages
	private HashMap<Locale, HashMap<String, String>> messages = new HashMap<Locale, HashMap<String,String>>();

	//InMemory storage of where messages were translated
	private HashMap<String, String> origins = new HashMap<String,String>();

	private OrderedConfiguration<Resource> allResources;

	private Resource t5aTranslation;

	private Context context;
	
	public MessageInterceptorStorageImp( Context context ) {
		this.context = context;
	}

	public Messages getMessages( Locale locale ) {
		if (messages.containsKey( locale )) {
			HashMap<String, String> map = messages.get( locale );
			return new MapMessages( locale, map );
		}
		return null;
	}

	public synchronized void addMsg( String key, String value, String pageName, Locale locale ) {
		HashMap<String, String> msgs = messages.get( locale );
		if ( msgs==null ) {
			msgs = new HashMap<String, String>();
		}
		msgs.put( key, value );
		messages.put( locale, msgs );
		origins.put( key, pageName );
	}

	public List<TranslatedMessageVO> getAllTranslatedMessages(  ) {
		final ArrayList<TranslatedMessageVO> msgs = new ArrayList<TranslatedMessageVO>();
		for (final Locale loc : messages.keySet()) {
			final Map<String, String> values = messages.get(loc); 
			for (final String key : values.keySet()) {
				msgs.add(new TranslatedMessageVO(key, values.get(key), origins.get(key), loc));
			}
		}
		return msgs;
	}

	public void save(  ) throws IOException {
		Map<String, String> msgPairs = new HashMap<String, String>();
		File translations = context.getRealFile(t5aTranslation.getPath());
		boolean exists = translations.exists();

		//Read existing content
		//
		if (exists) {

			FileInputStream fis = new FileInputStream(translations);
			InputStreamReader in = new InputStreamReader(fis, "UTF-8");
			BufferedReader br = new BufferedReader(in);

			logger.debug(translations.getAbsolutePath() + " does exist!!");
			//Read the file...
			String line = null;
			while ((line = br.readLine()) != null) {
				String[] split = line.split("=", 2);
				if (split.length > 1) {
					msgPairs.put(split[0], split[1]);
				}
			}
			
			br.close();
			in.close(); //Just in case :)

		} else {
			logger.debug(translations.getAbsolutePath() + " does NOT exist!!");
			//Who cares?!?
		}

		//Add in-memory translations
		//
		Locale[] langs = messages.keySet().toArray(new Locale[]{});
		if (langs.length > 0) {
			HashMap<String, String> knownPairs = messages.get(langs[0]);
			for (String key : knownPairs.keySet()) {
				String entry = knownPairs.get(key);
				msgPairs.put(key, entry);
			}
			messages.remove(langs[0]);
		}

		//Write the combined sets to file
		//
		FileOutputStream fos = new FileOutputStream(translations);
		OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
		BufferedWriter bw = new BufferedWriter(out);

		bw.write("#This file is generated automatically, do not attempt to manually edit, changes are likely to be overwritten!!");
		bw.newLine();

		for (String key : msgPairs.keySet()) {
			logger.debug("Writing message for key:" + key);
			bw.write(key);
			bw.write('=');
			bw.write(escape(msgPairs.get(key)));
			bw.newLine();
		}
		
		bw.close();
		out.close(); //Just in case :)
	}
	
	private String escape(String in) {
		return in.replaceAll("(=|\\\\)","\\$1");
	}

	public boolean addKnownMessageResource( 
			OrderedConfiguration<Resource> all
			, Resource t5aTranslation
	) {
		this.allResources = all;
		this.t5aTranslation = t5aTranslation;
		return true;
	}

}
